/*
 * SocketException.h
 *
 *  Created on: May 10, 2013
 *      Author: Lucifer
 */

#ifndef SOCKETEXCEPTION_H_
#define SOCKETEXCEPTION_H_

namespace BFX
{


/**
 * Defines error codes for socket module
 */
enum SocketError
{
	/// Success
	SocketError_Success						= 0,
	/// Unspecified error
	SocketError_UnspecifiedError			= -1,

	/// A blocking socket call was canceled.
	SocketError_Interrupted					= (10000+4),	// WSAEINTR				| EINTR
	/// Permission denied
	SocketError_AccessDenied				= (10000+13),	// EACCES				| EACCES
	/// Bad address.
	SocketError_Fault						= (10000+14),	// WSAEFAULT			| EFAULT
	/// Invalid argument.
	SocketError_InvalidArgument				= (10000+22),	// WSAEINVAL			| EINVAL
	/// Too many open files.
	SocketError_TooManyOpenSockets			= (10000+24),	// WSAEMFILE			| EMFILE, ENFILE
	/// Resource temporarily unavailable.
	SocketError_WouldBlock					= (10000+35),	// WSAEWOULDBLOCK		| EWOULDBLOCK
	/// Operation now in progress.
	SocketError_InProgress					= (10000+36),	// WSAEINPROGRESS		| EINPROGRESS
	/// Operation already in progress.
	SocketError_AlreadyInProgress			= (10000+37),	// WSAEALREADY			| EALREADY
	/// Socket operation on non-socket.
	SocketError_NotSocket					= (10000+38),	// WSAENOTSOCK			| ENOTSOCK
	/// The specified protocol is the wrong type for this socket.
	SocketError_ProtocolType				= (10000+41),	// WSAEPROTOTYPE		| EPROTOTYPE
	/// Protocol not supported.
	SocketError_ProtocolNotSupported		= (10000+43),	// WSAEPROTONOSUPPORT	| EPROTONOSUPPORT
	/// Socket type not supported.
	SocketError_SocketNotSupported			= (10000+44),	// WSAESOCKTNOSUPPORT
	/// Protocol family not supported.
	SocketError_ProtocolFamilyNotSupported	= (10000+46),	// WSAEPFNOSUPPORT
	/// Address family not supported by protocol family.
	SocketError_AddressFamilyNotSupported	= (10000+47),	// WSAEAFNOSUPPORT		| EAFNOSUPPORT
	/// Address already in use.
	SocketError_AddressAlreadyInUse			= (10000+48),	// WSAEADDRINUSE		| EADDRINUSE
	/// Cannot assign requested address.
	SocketError_AddressNotAvailable			= (10000+49),	// WSAEADDRNOTAVAIL		| EADDRNOTAVAIL
	/// Network is down.
	SocketError_NetworkDown					= (10000+50),	// WSAENETDOWN			| ENETDOWN
	/// Network is unreachable.
	SocketError_NetworkUnreachable			= (10000+51),	// WSAENETUNREACH		| ENETUNREACH
	/// Software caused connection to abort.
	SocketError_ConnectionAborted			= (10000+53),	// WSAECONNABORTED		| ECONNABORTED
	/// No buffer space available.
	SocketError_NoBufferSpaceAvailable		= (10000+55),	// WSAENOBUFS			| ENOBUFS, ENOMEM
	/// Socket is already connected.
	SocketError_IsConnected					= (10000+56),	// WSAEISCONN			| EISCONN
	/// Socket is not connected.
	SocketError_NotConnected				= (10000+57),	// WSAENOTCONN			| ENOTCONN
	/// Cannot send after socket shutdown.
	SocketError_Shutdown					= (10000+58),	// WSAESHUTDOWN
	/// Connection timed out.
	SocketError_TimedOut					= (10000+60),	// WSAETIMEDOUT			| ETIMEDOUT
	/// Connection refused.
	SocketError_ConnectionRefused			= (10000+61),	// WSAECONNREFUSED		| ECONNREFUSED
	/// Host is down.
	SocketError_HostDown					= (10000+64),	// WSAEHOSTDOWN
	/// No route to host.
	SocketError_HostUnreachable				= (10000+65),	// WSAEHOSTUNREACH		| EHOSTUNREACH
	/// Successful startup not yet performed.
	SocketError_NotInitialized				= (10000+93),	// WSANOTINITIALISED

	//
	// WIN32 dependent errors
	//

	/// Overlapped operations will complete later.
	SocketError_IOPending					= (997),	// ERROR_IO_PENDING
	// TODO: xxx
};

/**
 * The exception that is thrown when a socket error occurs.
 */
class SocketException: public SystemException
{
public:
	/**
	 * Initializes a new instance of the SocketException class with the last operating system error code.
	 */
	SocketException();
	/**
	 * Initializes a new instance of the SocketException class with the specified error code.
	 * @param nErrorCode
	 */
	SocketException(int nErrorCode);
	/**
	 * Initializes a new instance of the SocketException class with the specified SocketError value.
	 * @param socketError
	 */
	SocketException(SocketError socketError);
	virtual ~SocketException() throw();

	/**
	 * The category name of this exception.
	 * @return
	 */
	virtual const char* GetExceptionName() const
	{
		return "SocketException";
	}

	/**
	 * Gets the BFX::SocketError value that is associated with this exception.
	 * @return The BFX::SocketError value that is associated with this exception.
	 */
	SocketError GetSocketError() const;

	/**
	 * Gets the error code for this thread's last system sockets operation that failed, and translates to a value
	 * defined in BFX::SocketError.
	 * @return One of the BFX::SocketError values indicates the error code for this thread's last system sockets
	 * operation that failed.
	 */
	static SocketError GetLastSocketError();
	/**
	 * Translates the system error code to a value defined in BFX::SocketError.
	 * @param[in] nErrorCode
	 * @return One of the BFX::SocketError values.
	 */
	static SocketError TranslateErrorCode(int nErrorCode);
	/**
	 * Translates a value defined in BFX::SocketError to a system error code.
	 * @param[in] socketError
	 * @return The system error code.
	 */
	static int TranslateSocketError(SocketError socketError);

private:
	SocketError	m_socketError;
};

} /* namespace BFX */

#endif /* SOCKETEXCEPTION_H_ */
